package net.projectRPG.src;
import com.jme3.export.Savable;
import com.jme3.export.binary.BinaryImporter;
import com.jme3.export.binary.BinaryExporter;
import java.io.Serializable;
import java.io.IOException;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.InputCapsule;
import com.jme3.export.OutputCapsule;
import com.jme3.scene.Geometry;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.math.Matrix3f;
import com.jme3.math.Ray;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.PhysicsTickListener;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.scene.Spatial;
import com.jme3.renderer.Camera;
import com.jme3.math.Vector3f;
import com.jme3.bullet.control.RigidBodyControl;

public class Player extends Creature implements Savable, PhysicsCollisionListener, PhysicsTickListener  {
    
    public InteractableControl carriedObject;   
    private Main main;
    private Camera cam;
    public boolean left = false, right = false, up = false, down = false, jump = false, crouch = false, run = false;
    public float maxReach = 4.0f;
    public float holdDistance = 2.0f;
    public float playerSpeed = 0.05f;
    public boolean jumping = false;
    
    public Player (CollisionShape shape, float stepHeight, Main app)
    {
        super(shape, stepHeight, app);
        main = app;
        carriedObject = null;
        cam = main.getCamera();
    }
    
    public void setPhysicsSpace(PhysicsSpace space) {
        super.setPhysicsSpace(space);
        if (space != null) {
            space.addCollisionListener(this);
        }
    }    
    
    public void collision(PhysicsCollisionEvent event) {
        if (space == null) {
            super.space = this.getPhysicsSpace();
        }
        
       //  main.player.carriedObject = null;
        /*
        System.out.println(event.getObjectA());
        System.out.println(event.getObjectB());
        System.out.println("Player Impact: " + event.getAppliedImpulse());
        */

    }       
    
    public void simpleUpdatePlayer(float tpf){
        float speed = playerSpeed;
        Vector3f moveDir = new Vector3f(0,0,0);         
        
        if(crouch)
        {
          speed = playerSpeed / 2.0f;
        }
        if(run)
        {
          speed = playerSpeed * 10f;;
        }
    
        if(cam.getLocation().y > main.currentArea.waterLevel + 0.2f)
        {
            if(this.onGround())
            {
                jumping = false;
                if (up)    { moveDir.z = 1; }
                if (down)    { moveDir.z = -1; }
                if (left)    { moveDir.x = 1; }
                if (right)    { moveDir.x = -1; }
                walkDirection = (cam.getDirection().mult(moveDir.getZ()).setY(0.0f).normalize().add(cam.getLeft().mult(moveDir.getX())).normalize());
                setWalkDirection(walkDirection.multLocal(speed));
                if (jump)  {
                    jumping = true;
                    jump();
                }
            }else{
              // this is used to prevent floating away when swimming out of water
              if(jumping = false)
              {
                setWalkDirection(new Vector3f(0f,0f,0f));
              }
            }
        }else{
                if (up)    { moveDir.z = 1; }
                if (down)    { moveDir.z = -1; }
                if (left)    { moveDir.x = 1; }
                if (right)    { moveDir.x = -1; }
                walkDirection = new Vector3f (0,0,0);
                walkDirection = cam.getDirection().mult(moveDir.getZ());
                if(left || right)
                    walkDirection = walkDirection.add(cam.getLeft().mult(moveDir.getX()));
            if(jump)
                walkDirection = new Vector3f(walkDirection.x, 2f, walkDirection.z);
            if(crouch)
                walkDirection = new Vector3f(walkDirection.x, 2f, walkDirection.z);
            
            setWalkDirection(walkDirection.multLocal(speed));
        }
        System.err.println(walkDirection);          
        cam.setLocation(getPhysicsLocation());

        // if underwater, players float and sink gradually
        if(cam.getLocation().y < main.currentArea.waterLevel)
        {
            setGravity(0f);
            setFallSpeed(.4f);
        }else{
            setGravity(main.globalGravity);
            setFallSpeed(main.globalFallSpeed);
        }        
        
        // deal with carried objects

        if(carriedObject != null)
        {
          RigidBodyControl object = carriedObject;
          //object.setPhysicsLocation(new Vector3f(cam.getDirection().getX(),0,cam.getDirection().getZ()).normalizeLocal().multLocal(1.5f));
            Vector3f camPos = cam.getLocation();
            Vector3f camDir = cam.getDirection();
            Vector3f newPos = new Vector3f();
            newPos.setX(camPos.getX() + holdDistance * camDir.getX());
            newPos.setY(camPos.getY() + holdDistance * camDir.getY());
            newPos.setZ(camPos.getZ() + holdDistance * camDir.getZ());

              System.out.println(carriedObject);
            try{
              object.setPhysicsLocation(newPos);
              object.setPhysicsRotation(cam.getRotation());
            }catch (Exception e){
              System.out.println("WARNING: " + e.getMessage());
            }
        }
    }
    
    @Override
    public void prePhysicsTick(PhysicsSpace space, float f){

    }
    
    @Override
    public void physicsTick(PhysicsSpace space, float f) {

    }        
    
    public void write(JmeExporter ex) throws IOException {
        super.write(ex);
    }

    public void read(JmeImporter im) throws IOException {
        super.read(im);
    }    

}